/*
 * FaceCat图形通讯框架(非开源)
 * 著作权编号:2015SR229355+2020SR0266727
 * 上海卷卷猫信息技术有限公司
 */

#include "stdafx.h"
#include "FCUIXml.h"

namespace FaceCat{
    static ArrayList<FCUIXml*> m_nameXmls;
	
    void FCUIXml::createMenuItem(XMLElement *node, FCMenu *menu, FCMenuItem *parentItem){
		FCMenuItem *item = new FCMenuItem;
		item->setNative(m_native);
		setAttributesBefore(node, item);
		if (parentItem){
			parentItem->addItem(item);
		}
		else{
			menu->addItem(item);
		}
        XMLElement *spChildNode = node->FirstChildElement();
        while (spChildNode){
            createMenuItem(spChildNode, menu, item);
            spChildNode = spChildNode->NextSiblingElement();
        }
		setAttributesAfter(node, item);
		onAddView(item, node);
	}
    
	void FCUIXml::createGridColumns(XMLElement *node, FCView *view)
	{
		FCGrid *grid = dynamic_cast<FCGrid*>(view);
        XMLElement *spChildNode = node->FirstChildElement();
        while (spChildNode){
            String subNodeName = FCTran::stringToString(spChildNode->Name());
			FCView *subView = createView(spChildNode, FCTran::toLower(subNodeName));
			FCGridColumn *column = dynamic_cast<FCGridColumn*>(subView);
			if(column){
				column->setNative(m_native);
				grid->addColumn(column);
			}
			setAttributesBefore(spChildNode, column);
			readChildNodes(spChildNode, column);
			setAttributesAfter(spChildNode, column);
			onAddView(column, spChildNode);
			String subNodeValue = L"";
            if(spChildNode->GetText()){
                subNodeValue = FCTran::stringToString(spChildNode->GetText());
            }
            if ((int)subNodeValue.length() > 0){
                column->setText(subNodeValue);
            }
            spChildNode = spChildNode->NextSiblingElement();
        }
	}
	
	void FCUIXml::createGridRow(XMLElement *node, FCView *view){
		FCGrid *grid = dynamic_cast<FCGrid*>(view);
		FCGridRow *row = new FCGridRow;
		grid->addRow(row);
		setAttributesBefore(node, row);
        int col = 0;
        XMLElement *spChildNode2 = node->FirstChildElement();
        while (spChildNode2){
            String subNodeName = FCTran::stringToString(spChildNode2->Name());
			String subNodeValue = L"";
            if(spChildNode2->GetText()){
                subNodeValue = FCTran::stringToString(spChildNode2->GetText());
            }
			if(subNodeName == L"cell" || subNodeName == L"td"){
				String cellType = L"string";
                const XMLAttribute *atrNode = spChildNode2->FirstAttribute();
                while (atrNode){
                    String strName = FCTran::stringToString(atrNode->Name());
                    if(strName == L"type"){
                        cellType = FCTran::stringToString(atrNode->Value());
                        break;
                    }
                    atrNode = atrNode->Next();
                }
				FCGridCell *cell = 0;
				if (cellType == L"bool"){
					cell = new FCGridBoolCell;
				}
				else if (cellType == L"button"){
					cell = new FCGridButtonCell;
				}
				else if (cellType == L"checkbox"){
					cell = new FCGridCheckBoxCell;
				}
				else if (cellType == L"double"){
					cell = new FCGridDoubleCell;
                }
				else if (cellType == L"float"){
					cell = new FCGridFloatCell;
				}
				else if (cellType == L"string"){
					cell = new FCGridStringCell;
				}
				else if (cellType == L"int"){
					cell = new FCGridIntCell;
				}
				else if (cellType == L"long"){
					cell = new FCGridLongCell;
				}
				else if (cellType == L"textbox"){
					cell = new FCGridTextBoxCell;
				}
                else if (cellType == L"percent"){
                    cell = new FCGridPercentCell;
                }
				row->addCell(col, cell);
				setAttributesBefore(spChildNode2, cell);
				cell->setString(subNodeValue);
				setAttributesAfter(spChildNode2, cell);
				col++;
			}
            spChildNode2 = spChildNode2->NextSiblingElement();
        }
		setAttributesAfter(node, row);
	}
    
	void FCUIXml::createGridRows(XMLElement *node, FCView *view){
        XMLElement *spChildNode = node->FirstChildElement();
        while (spChildNode){
            String nodeName = FCTran::stringToString(spChildNode->Name());
			if(nodeName == L"row" || nodeName == L"tr"){
				createGridRow(spChildNode, view);
			}
            spChildNode = spChildNode->NextSiblingElement();
        }
	}
    
	void FCUIXml::createSplitLayoutSubAttribute(XMLElement *node, FCSplitLayoutDiv *splitLayoutDiv){
        setAttributesBefore(node, splitLayoutDiv);
		int oldCount = (int)splitLayoutDiv->m_views.size();
        readChildNodes(node, splitLayoutDiv);
		ArrayList<FCView*> newViews = splitLayoutDiv->m_views;
		int newCount = (int)newViews.size();
        if (newCount - oldCount >= 2){
            splitLayoutDiv->setFirstView(newViews.get(newCount - 2));
            splitLayoutDiv->setSecondView(newViews.get(newCount - 1));
        }
		setAttributesAfter(node, splitLayoutDiv);
        //splitLayoutDiv->update();
		onAddView(splitLayoutDiv, node);
	}
    
	void FCUIXml::createTabPage(XMLElement *node, FCView *view){
		FCTabView *tabView = dynamic_cast<FCTabView*>(view);
		if(tabView){
			FCTabPage *tabPage = new FCTabPage;
			tabPage->setNative(m_native);
			tabView->addView(tabPage);
			setAttributesBefore(node, tabPage);
			readChildNodes(node, tabPage);
			setAttributesAfter(node, tabPage);
			onAddView(tabPage, node);
		}
	}
    
    void FCUIXml::createTreeNode(XMLElement *node, FCView *view, FCTreeNode *treeNode){
	    FCTree *tree = dynamic_cast<FCTree*>(view);
        if (tree){
			FCTreeNode *appendNode = new FCTreeNode;
            if (treeNode){
				treeNode->appendNode(appendNode);
            }
            else{
				tree->appendNode(appendNode);
            }
            setAttributesBefore(node, appendNode);
            XMLElement *spChildNode = node->FirstChildElement();
            while (spChildNode){
                String nodeName = FCTran::stringToString(spChildNode->Name());
                if(nodeName == L"node"){
					createTreeNode(spChildNode, view, appendNode);
				}
                spChildNode = spChildNode->NextSiblingElement();
            }
			setAttributesAfter(node, appendNode);
        }
	}
    
	void FCUIXml::createTreeNodes(XMLElement *node, FCView *view){
        XMLElement *spChildNode = node->FirstChildElement();
        while (spChildNode){
            createTreeNode(spChildNode, view, 0);
            spChildNode = spChildNode->NextSiblingElement();
        }
	}
    
	FCView* FCUIXml::createCustomView(XMLElement *node){
		FCView *customView = 0;
        const XMLAttribute *atrNode = node->FirstAttribute();
        while (atrNode){
            String strName = FCTran::stringToString(atrNode->Name());
            if(strName == L"cid"){
                String strValue = FCTran::stringToString(atrNode->Value());
                customView = createView(node, strValue);
                break;
            }
            atrNode = atrNode->Next();
        }
        if (customView){
            return customView;
        }
        else{
            return new FCView;
        }
	}
    
	///////////////////////////////////////////////////////////////////////////////////////////////////////
    
	FCUIXml::FCUIXml(){
		m_native = 0;
        m_allowName = true;
	}
    
	FCUIXml::~FCUIXml(){
        if((int)m_name.length() > 0){
            for(int i = 0; i < m_nameXmls.size(); i++){
                FCUIXml *uiXml = m_nameXmls.get(i);
                if(uiXml == this){
                    m_nameXmls.removeAt(i);
                    break;
                }
            }
        }
		m_views.clear();
		m_native = 0;
	}
    
	FCNative* FCUIXml::getNative(){
		return m_native;
	}
    
	void FCUIXml::setNative(FCNative *value){
		m_native = value;
	}
    
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
	FCButton* FCUIXml::getButton(const String& name){
		FCView *view = findView(name);
        if (view){
            return dynamic_cast<FCButton*>(view);
        }
        return 0;
	}
    
    FCChart* FCUIXml::getChart(const String& name){
        FCView *view = findView(name);
        if (view){
            return dynamic_cast<FCChart*>(view);
        }
        return 0;
    }
    
	FCCheckBox* FCUIXml::getCheckBox(const String& name){
		FCView *view = findView(name);
        if (view){
            return dynamic_cast<FCCheckBox*>(view);
        }
        return 0;
	}
    
    FCComboBox* FCUIXml::getComboBox(const String& name){
		FCView *view = findView(name);
        if (view){
            return dynamic_cast<FCComboBox*>(view);
        }
        return 0;
	}
    
    FCDiv* FCUIXml::getDiv(const String& name){
		FCView *view = findView(name);
        if (view){
            return dynamic_cast<FCDiv*>(view);
        }
        return 0;
	}
    
	FCGrid* FCUIXml::getGrid(const String& name){
		FCView *view = findView(name);
        if (view){
            return dynamic_cast<FCGrid*>(view);
        }
        return 0;
	}
    
	FCLabel* FCUIXml::getLabel(const String& name){
		FCView *view = findView(name);
        if (view){
            return dynamic_cast<FCLabel*>(view);
        }
        return 0;
	}
    
	FCLayoutDiv* FCUIXml::getLayoutDiv(const String& name){
		FCView *view = findView(name);
        if (view){
            return dynamic_cast<FCLayoutDiv*>(view);
        }
        return 0;
	}
    
	ArrayList<FCView*> FCUIXml::getLikeViews(const String& name)
	{
		ArrayList<FCView*> views;
        for(int c = 0; c < m_views.size(); c++){
			FCView *view = m_views.get(c);
			if(view->getName().find(name) != -1){
				views.add(view);
			}
		}
        return views;
	}
    
    FCMenu* FCUIXml::getMenu(const String& name){
		FCView *view = findView(name);
        if (view){
            return dynamic_cast<FCMenu*>(view);
        }
        return 0;
	}
    
	FCMenuItem* FCUIXml::getMenuItem(const String& name){
		FCView *view = findView(name);
        if (view){
            return dynamic_cast<FCMenuItem*>(view);
        }
        return 0;
	}
                                        
	FCRadioButton* FCUIXml::getRadioButton(const String& name){
		FCView *view = findView(name);
        if (view){
            return dynamic_cast<FCRadioButton*>(view);
        }
        return 0;
	}
    
    FCSpin* FCUIXml::getSpin(const String& name){
		FCView *view = findView(name);
        if (view){
            return dynamic_cast<FCSpin*>(view);
        }
        return 0;
	}
    
	FCSplitLayoutDiv* FCUIXml::getSplitLayoutDiv(const String& name){
		FCView *view = findView(name);
        if (view){
            return dynamic_cast<FCSplitLayoutDiv*>(view);
        }
        return 0;
	}
    
	FCTabView* FCUIXml::getTabView(const String& name){
		FCView *view = findView(name);
        if (view){
            return dynamic_cast<FCTabView*>(view);
        }
        return 0;
	}
    
	FCTabPage* FCUIXml::getTabPage(const String& name){
		FCView *view = findView(name);
        if (view){
            return dynamic_cast<FCTabPage*>(view);
        }
        return 0;
	}
    
	FCTextBox* FCUIXml::getTextBox(const String& name){
		FCView *view = findView(name);
        if (view){
            return dynamic_cast<FCTextBox*>(view);
        }
        return 0;
	}
    
    FCTree* FCUIXml::getTree(const String& name){
		FCView *view = findView(name);
        if (view){
            return dynamic_cast<FCTree*>(view);
        }
        return 0;
	}
    
	FCWindow* FCUIXml::getWindow(const String& name){
	    FCView *view = findView(name);
        if (view){
            return dynamic_cast<FCWindow*>(view);
        }
        return 0;
	}
    
    FCUIXml* FCUIXml::getNameXml(const String& name){
        for(int i = 0; i < m_nameXmls.size(); i++){
            FCUIXml *uiXml = m_nameXmls.get(i);
            if (uiXml->m_name == name)
            {
                return uiXml;
            }
        }
        return 0;
    }

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
	bool FCUIXml::containsView(FCView *view){
        for(int c = 0; c < m_views.size(); c++){
			if(view == m_views.get(c)){
				return true;
			}
		}
		return false;
	}
    
	FCView* FCUIXml::createView(XMLElement *node, const String& type){
        int typeLen = (int)type.length();
        switch (typeLen)
        {
            case 1:
                {
                    if (type == L"a")
                    {
                        return new FCLinkLabel();
                    }
                    break;
                }
            case 2:
                {
                    if (type == L"th")
                    {
                        return new FCGridColumn();
                    }
                    break;
                }
            case 3:
                {
                    if (type == L"div")
                    {
                        const XMLAttribute *atrNode = node->FirstAttribute();
                        while (atrNode){
                            String strName = FCTran::stringToString(atrNode->Name());
                            if(strName == L"type"){
                                String inputType = FCTran::stringToString(atrNode->Value());
                                if (inputType == L"layout")
                                {
                                    return new FCLayoutDiv();
                                }
                                else if (inputType == L"splitlayout")
                                {
                                    return new FCSplitLayoutDiv();
                                }
                                else if (inputType == L"tab")
                                {
                                    return new FCTabView();
                                }
                                else if (inputType == L"tabpage")
                                {
                                    return new FCTabPage();
                                }
                                else if (inputType == L"custom")
                                {
                                    return createCustomView(node);
                                }
                                break;
                            }
                            atrNode = atrNode->Next();
                        }
                        return new FCDiv();
                    }
                    else if (type == L"tab")
                    {
                        return new FCTabView();
                    }
                    break;
                }
            case 4:
                {
                    if (type == L"grid")
                    {
                        return new FCGrid();
                    }
                    else if (type == L"menu")
                    {
                        return new FCMenu();
                    }
                    else if (type == L"spin")
                    {
                        return new FCSpin();
                    }
                    else if (type == L"tree")
                    {
                        return new FCTree();
                    }else if(type == L"view"){
                        const XMLAttribute *atrNode = node->FirstAttribute();
                        while (atrNode){
                            String strName = FCTran::stringToString(atrNode->Name());
                            if(strName == L"type"){
                                String inputType = FCTran::stringToString(atrNode->Value());
                                if (inputType == L"layout")
                                {
                                    return new FCLayoutDiv();
                                }
                                else if (inputType == L"splitlayout")
                                {
                                    return new FCSplitLayoutDiv();
                                }
                                else if (inputType == L"tab")
                                {
                                    return new FCTabView();
                                }
                                else if (inputType == L"tabpage")
                                {
                                    return new FCTabPage();
                                }
                                else if (inputType == L"button")
                                {
                                    return new FCButton();
                                }
                                else if (inputType == L"checkbox")
                                {
                                    return new FCCheckBox();
                                }
                                else if (inputType == L"datetime")
                                {
                                    return new FCDateTimePicker();
                                }
                                else if (inputType == L"radio")
                                {
                                    return new FCRadioButton();
                                }
                                else if (inputType == L"range")
                                {
                                    return new FCSpin();
                                }
                                else if (inputType == L"text")
                                {
                                    return new FCTextBox();
                                }
                                else if (inputType == L"custom")
                                {
                                    return createCustomView(node);
                                }
                                break;
                            }
                            atrNode = atrNode->Next();
                        }
                        return new FCDiv();
                    }
                    break;
                }
            case 5:
                {
                    if (type == L"chart")
                    {
                        return new FCChart();
                    }
                    else if (type == L"table")
                    {
                        return new FCGrid();
                    }
                    else if (type == L"input")
                    {
                        const XMLAttribute *atrNode = node->FirstAttribute();
                        while (atrNode){
                            String strName = FCTran::stringToString(atrNode->Name());
                            if(strName == L"type"){
                                String inputType = FCTran::stringToString(atrNode->Value());
                                if (inputType == L"button")
                                {
                                    return new FCButton();
                                }
                                else if (inputType == L"checkbox")
                                {
                                    return new FCCheckBox();
                                }
                                else if (inputType == L"datetime")
                                {
                                    return new FCDateTimePicker();
                                }
                                else if (inputType == L"radio")
                                {
                                    return new FCRadioButton();
                                }
                                else if (inputType == L"range")
                                {
                                    return new FCSpin();
                                }
                                else if (inputType == L"text")
                                {
                                    return new FCTextBox();
                                }
                                else if (inputType == L"custom")
                                {
                                    return createCustomView(node);
                                }
                                break;
                            }
                            atrNode = atrNode->Next();
                        }
                    }
                    else if (type == L"label")
                    {
                        return new FCLabel();
                    }
                    break;
                }
            case 6:
                {
                    if (type == L"button")
                    {
                        return new FCButton();
                    }
                    else if (type == L"column")
                    {
                        return new FCGridColumn();
                    }
                    else if (type == L"select")
                    {
                        return new FCComboBox();
                    }
                    else if (type == L"custom")
                    {
                        return createCustomView(node);
                    }
                    else if (type == L"window")
                    {
                        return new FCWindow();
                    }
                    break;
                }
            case 7:
                {
                    if (type == L"textbox")
                    {
                        return new FCTextBox();
                    }
                    break;
                }
        }
        if (typeLen > 7)
        {
            if (type == L"calendar")
            {
                return new FCCalendar();
            }
            else if (type == L"checkbox")
            {
                return new FCCheckBox();
            }
            else if (type == L"combobox")
            {
                return new FCComboBox();
            }
            else if (type == L"datepicker")
            {
                return new FCDateTimePicker();
            }
            else if (type == L"layoutdiv")
            {
                return new FCLayoutDiv();
            }
            else if (type == L"linklabel")
            {
                return new FCLinkLabel();
            }
            else if (type == L"splitlayoutdiv")
            {
                return new FCSplitLayoutDiv();
            }
            else if (type == L"radiobutton")
            {
                return new FCRadioButton();
            }
        }
        return 0;
    }
    
	void FCUIXml::createNative(){
		m_native = new FCNative;
	}
    
	void FCUIXml::createSubAttribute(XMLElement *node, FCView *view){
		String strName = FCTran::stringToString(node->Name());
		if (strName == L"columns"){
            if (dynamic_cast<FCGrid*>(view)){
				createGridColumns(node, view);
            }
        }
		else if(strName == L"item" || strName == L"option"){
			if(dynamic_cast<FCComboBox*>(view)){
				FCComboBox *comboBox = dynamic_cast<FCComboBox*>(view);
				if(comboBox){
					createMenuItem(node, comboBox->getDropDownMenu(), 0);
				}
			}
			else if (dynamic_cast<FCMenu*>(view)){
                FCMenu *menu = dynamic_cast<FCMenu*>(view);
                if (menu){
                    createMenuItem(node, menu, 0);
                }
            }
		}
		else if(strName == L"nodes"){
			if(dynamic_cast<FCTree*>(view)){
				createTreeNodes(node, view);
			}
		}
		else if (strName == L"rows"){
            if (dynamic_cast<FCGrid*>(view)){
				createGridRows(node, view);
            }
        }
		else if(strName == L"tabpage"){
			if(dynamic_cast<FCTabView*>(view)){
				createTabPage(node, view);
			}
		}
	    else if (strName == L"tr"){
            if (dynamic_cast<FCGrid*>(view)){
                FCGrid *grid = dynamic_cast<FCGrid*>(view);
                if ((int)grid->m_columns.size() == 0){
                    createGridColumns(node, view);
                }
                else{
                    createGridRow(node, view);
                }
            }
        }
	}
    
	FCView* FCUIXml::findView(const String& name){
        for(int c = 0; c < m_views.size(); c++){
			FCView *view = m_views.get(c);
			if(view->getName() == name){
				return view;
			}
		}
		return 0;
	}
    
	HashMap<String, String> FCUIXml::getAttributes(XMLElement *node){
		HashMap<String, String> matrs;
        const XMLAttribute *atrNode = node->FirstAttribute();
        while (atrNode){
            String strName = FCTran::stringToString(atrNode->Name());
            String strValue = FCTran::stringToString(atrNode->Value());
            matrs.put(strName, strValue);
            atrNode = atrNode->Next();
        }
		return matrs;
	}
    
	ArrayList<FCView*> FCUIXml::getViews(){
		ArrayList<FCView*> views;
		if(m_native){
			views = m_native->m_views;
		}
		return views;
	}
    
	bool FCUIXml::isAfterSetingAttribute(const String& name)
    {
        int nameLength = (int)name.length();
        if(nameLength > 0){
            wchar_t fir = name[0];
            if(fir == 's' || fir == 'v' || fir == 'c'){
                switch (nameLength) {
                    case 4:
                        if(name == L"value"){
                            return true;
                        }
                        break;
                    case 7:
                        if(name == L"checked"){
                            return true;
                        }
                        break;
                    case 12:
                        if(name == L"selectedtext"){
                            return true;
                        }
                        break;
                    case 13:
                        if (name == L"selectedindex"
                            || name == L"selectedvalue"){
                            return true;
                        }
                        break;
                }
            }
        }
        return false;
	}
    
	void FCUIXml::loadFile(const String& fileName, FCView *view){
		m_views.clear();
        lstring xmlFileName = FCTran::StringTostring(fileName);
        XMLDocument doc;
        if(doc.LoadFile(xmlFileName.c_str()) != 0){
            return;
        }
        XMLElement* node = doc.RootElement();
        XMLElement *spChildNode = node->FirstChildElement();
        while (spChildNode){
            String nodeName = FCTran::stringToString(spChildNode->Name());
            if(nodeName == L"body"){
                readBody(spChildNode, view);
            }
            spChildNode = spChildNode->NextSiblingElement();
        }
    }
    
	void FCUIXml::readBody(XMLElement *node, FCView *view)
	{
        if(m_allowName){
            HashMap<String, String> attributes = getAttributes(node);
            if (attributes.containsKey(L"name"))
            {
                m_name = attributes.get(L"name");
                m_nameXmls.add(this);
            }
        }
        XMLElement *spChildNode = node->FirstChildElement();
        while (spChildNode){
            readNode(spChildNode, view);
            spChildNode = spChildNode->NextSiblingElement();
        }
	}
    
	void FCUIXml::onAddView(FCView *view, XMLElement *node){
		m_views.add(view);
	}
    
	void FCUIXml::readChildNodes(XMLElement *node, FCView *view){
        XMLElement *spChildNode = node->FirstChildElement();
        while (spChildNode){
            readNode(spChildNode, view);
            spChildNode = spChildNode->NextSiblingElement();
        }
	}
	
	FCView* FCUIXml::readNode(XMLElement *node, FCView* parent){
		String nodeName = FCTran::stringToString(node->Name());
		nodeName = FCTran::toLower(nodeName);
		FCView *view = createView(node, nodeName);
		if(view){
			view->setNative(m_native);
            if (parent){
                parent->addView(view);
            }
            else{
                m_native->addView(view);
            }
			setAttributesBefore(node, view);
            FCSplitLayoutDiv *splitLayoutDiv = dynamic_cast<FCSplitLayoutDiv*>(view);
            if(splitLayoutDiv){
                createSplitLayoutSubAttribute(node, splitLayoutDiv);
            }else{
				readChildNodes(node, view);
			}
			setAttributesAfter(node, view);
            if(view->m_views.size() == 0){
                String nodeValue;
                if(node->GetText()){
                    nodeValue = FCTran::stringToString(node->GetText());
                }
                if((int)nodeValue.length() > 0){
                    view->setText(nodeValue);
                }
            }
			view->update();
			onAddView(view, node);
		}
		else{
			createSubAttribute(node, parent);
		}
		return view;
	}
	
	void FCUIXml::setAttributesAfter(XMLElement *node, FCAttribute *view)
	{
        const XMLAttribute *atrNode = node->FirstAttribute();
        while (atrNode){
            String strName = FCTran::stringToString(atrNode->Name());
            String strValue = FCTran::stringToString(atrNode->Value());
            if(isAfterSetingAttribute(strName)){
                view->setAttribute(FCTran::toLower(strName), strValue);
            }
            atrNode = atrNode->Next();
        }
	}
    
	void FCUIXml::setAttributesBefore(XMLElement *node, FCAttribute *view){
        const XMLAttribute *atrNode = node->FirstAttribute();
        while (atrNode){
            String strName = FCTran::stringToString(atrNode->Name());
            String strValue = FCTran::stringToString(atrNode->Value());
            if(!isAfterSetingAttribute(strName)){
                view->setAttribute(FCTran::toLower(strName), strValue);
            }
            atrNode = atrNode->Next();
        }
	}
}
